package com.linshidream.intrachat.simplenio.packet.boots;


import com.linshidream.intrachat.simplenio.packet.context.ConnectionContext;
import com.linshidream.intrachat.simplenio.packet.context.DefaultConnectionContext;
import com.linshidream.intrachat.simplenio.packet.handler.*;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created on 2025/8/18 08:08
 *
 * @author linshidream
 * @version 1.0.0
 * @description
 */

public class PacketBootstrap {

    private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);

    private final SocketChannel socketChannel;

    private final Selector selector;

    private ConnectionContext ctx;

    public PacketBootstrap() throws IOException {
        this.socketChannel = SocketChannel.open();
        this.socketChannel.configureBlocking(false);

        this.selector = Selector.open();
    }

    public PacketBootstrap handler(MessageCodec codec, PacketHandler handler) {
        try {
            ctx = new DefaultConnectionContext(socketChannel, selector, codec, handler);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return this;
    }

    public PacketBootstrap connect(String hostname, int port) throws IOException {
        socketChannel.connect(new InetSocketAddress(hostname, port));
        socketChannel.register(selector, SelectionKey.OP_CONNECT);

        return this;
    }

    public void send() {
        try {
            Scanner scanner = new Scanner(System.in);
            System.out.print("请输入你要发送的内容：");
            while (true) {
                String msg = scanner.nextLine();
                ByteBuffer buffer = this.ctx.codec().encode(msg);
//                this.ctx.channel().write(buffer);

                // 支持写监听模式
                this.ctx.writer().send(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void async() {
        SCHEDULER.schedule(this::start, 1, TimeUnit.MICROSECONDS);
    }

    private void start() {
        try {
            while (socketChannel.isOpen()) {
                // 每隔1s检查一下是否有可用通道
                int readyChannels = selector.select(1000);
                if (readyChannels == 0) {
                    continue;
                }

                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();

                    if (key.isConnectable()) {
                        SocketChannel channel = (SocketChannel) key.channel();

                        // 建立连接后，再订阅读事件
                        if (channel.finishConnect()) {
                            channel.register(selector, SelectionKey.OP_READ);
                            ctx.handler().channelActive(ctx);
                        }
                    }

                    if (key.isValid() && key.isReadable()) {
                        SocketChannel sc = (SocketChannel) key.channel();
                        // 目前客户端只有一个通道 就是客户端本身
                        PacketReader.doRead(ctx);
                    }

                    if (key.isValid() && key.isWritable()) {
                        SocketChannel sc = (SocketChannel) key.channel();
                        // 上次没写完继续写
                        this.ctx.writer().doWrite();
                    }
                }
            }

        } catch (Exception e) {
            ctx.handler().exceptionCaught(ctx, e);
        }
    }
}
